import { interceptorHeader, parseResponse, storageServerTime } from "../global/config.js"
import { interceptorRequest, interceptorResponse, errTips } from "./http_interceptor.js"
import { Throwable } from "../err_handle/throwable.js"

/**
 * 这个类不需要做任何修改，在http_interceptor.js和main.js中进行配置
 */
export class Http {
	
	get(url, data = {}, path = {}) {
		return this.request({url: url, data: data, path:path})
	}
	
	post(url, data = {}, path = {}) {
		return this.request({url: url, method: "POST", data: data, path:path})
	}
	
	put(url, data = {}, path = {}) {
		return this.request({url: url, method: "PUT", data: data, path:path})
	}
	
	postField(url, data = {}, path = {}) {
		return this.request({url: url, method: "POST", data: data, path:path, header: {"content-type": "application/x-www-form-urlencoded"}})
	}
	
	request({ url, method = "GET", path = {}, query = {}, data = {}, header = {} }) {
		return interceptorHeader(header)
		.then(() => {
			return new Promise((resolve, reject) => this._request(url, resolve, reject, method, path, query, data, header))
		})
		.then(res => parseResponse(res))
		.catch(reason => {
			let requestInfo = {
				url: url,
				method: method,
				header: header,
				path: path,
				query: query,
				data: data
			}
			reason.requestInfo = requestInfo
			return Promise.reject(reason)
		})
	}
	
	upload(url, filePath, fileKey, path = {}, query = {}, data = {}, header = {}) {
		return interceptorHeader(header)
		.then(() => {
			return new Promise((resolve, reject) => this._upload(url, filePath, fileKey, resolve, reject, path, query, data, header))
		})
		.then(res => parseResponse(res))
	}
	
	/**
	 * 统一在请求开始之前以及请求结束之后追加刷新登录态的逻辑
	 * showLoading: 是否显示微信loading效果
	 * author: true -> 网络请求之前会校验并刷新登录态 false -> 网络请求之前不会校验和刷新登录态
	 * backPage: 登录成功后跳转的目标页面，默认会获取当前页面路径，如果获取不到，则取值:pages/index/index
	 * backType: 取值 -> back、redirect、relaunch，登录成功后跳转目标页面的方式，默认为redirect
	 * autoUpdateLogin: 为true,请求业务接口时，若服务器返回未登录状态，会自动刷新登录状态，然后继续上一次请求，
	 * 未false，请求业务接口时，若服务器返回未登录状态，直接跳转到授权登录界面。
	 */
	interceptor(fun, {showLoading = false, placeholder = true, author = false, backPage, backType = "redirect", autoUpdateLogin = false}) {
		let pages = getCurrentPages()
		let currentPage = null
		if(pages && pages.length > 0) {
			currentPage = pages[pages.length - 1]
		}
		if(!backPage) {
			backPage = currentPage ? currentPage.route:"pages/index/index"
		}
		
		//fixed
		let backPageQuery = ""
		if(!backPageQuery) {
			let options = currentPage ? (currentPage.options || {}):{}
			
			for(let key in options) {
				backPageQuery += key + "=" + (options[key] || '') + "&"
			}
			if(backPageQuery.lastIndexOf("&") != -1) {
				backPageQuery = backPageQuery.substring(0, backPageQuery.lastIndexOf("&"))
			}
		}
		
		if(showLoading) {
			uni.showLoading()
		}
		
		if(placeholder && currentPage) {
			currentPage.$vm.isLoading = true
		}
		
		return interceptorRequest(author, this)
			.then(res => fun())
			.catch(reason => {
				reason.backPage = backPage
				reason.backType = backType
				reason.backPageQuery = backPageQuery
				return interceptorResponse(reason, fun, this, autoUpdateLogin)
			})
			.then(res => {
				return Promise.resolve(res)
			})
			.catch(reason => {
				reason.backPage = backPage
				reason.backType = backType
				reason.backPageQuery = backPageQuery
				return Promise.reject(reason)
			})
			.finally(() => {
				let timer = setTimeout(() => {
					if(placeholder && currentPage) {
						currentPage.$vm.isLoading = false
					} 
					if(showLoading) {
						uni.hideLoading()
					}
					clearTimeout(timer)
				}, 300)
			})
	}
	
	_request(url, resolve, reject, method = "GET", path = {}, query = {}, data = {}, header = {}) {
		header = Object.assign({"content-type": "application/json"}, header)
		// data = Object.assign({"pageSize": 20}, data)
		uni.request({
			url: this._processRequest(url, path, query),
			method: method,
			data: data,
			header: header,
			success: res => {
				this._handleSuccess(res, resolve, reject)
			},
			fail: err => {
				this._handleError(err, reject)
			}
		})
	}
	
	_upload(url, filePath, fileKey, resolve, reject, path = {}, query = {}, data = {}, header = {}) {
		header = Object.assign({"content-type": "multipart/form-data", 'Access-Control-Allow-Headers': '*'}, header)
		
		uni.uploadFile({
			url: this._processRequest(url, path, query),
			filePath: filePath,
			name: fileKey,
			formData: data,
			header: header,
			success: res => {
				this._handleUploadSuccess(res, resolve, reject)
			},
			fail: err => {
				this._handleError(err, reject)
			}
		})
	}
	
	_processRequest(url, path = {id: 1}, query = {}) {
		let queryStr = ""
		if(query) {
			for(let key in query) {
				queryStr += key + "=" + encodeURIComponent(query[key]) + "&"
			}
			if(queryStr.endsWith("&")) {
				queryStr = queryStr.substring(0, queryStr.lastIndexOf("&"))
			}
		}
		
		if(path) {
			for(let key in path) {
				url = url.replaceAll("{" + key + "}", path[key]);
			}
		}
		
		if(queryStr) {
			url = url + "?" + queryStr
		}
		
		return url
	}
	
	_handleSuccess(res, resolve, reject) {
		let code = res.statusCode + ""
		let date = res && res.header && res.header.Date ? res.header.Date:""
		let timeStamp = 0;
		if(date) {
			timeStamp = new Date(date).getTime()
		}
		console.log(date)
		storageServerTime(timeStamp)
		
		if(code.startsWith("2")) {
			//服务器返回结果正常,但是后端业务可能报错
			resolve(res.data)
		} else {
			/**
			 * 服务器异常
			 */
			reject(errTips[code] ? new Throwable(10000, errTips[code]) : new Throwable(10000, errTips[10000]))
		}
	}
	
	_handleUploadSuccess(res, resolve, reject) {
		let code = res.statusCode + ""
		if(code.startsWith("2")) {
			//服务器返回结果正常,但是后端业务可能报错
			resolve(JSON.parse(res.data))
		} else {
			/**
			 * 服务器异常
			 */
			reject(errTips[code] ? new Throwable(10000, errTips[code]) : new Throwable(10000, errTips[10000]))
		}
	}
	
	_handleError(err, reject) {
		//小程序接口调用错误
		reject(err && err.errMsg ? new Throwable(10001, err.errMsg) : new Throwable(10001, errTips[10001]))
	}
}